package inet

import (
	"bytes"

	"gitee.com/hasika/common-server/buffer"
	"gitee.com/hasika/gotool/errorx"
	"gitee.com/hasika/gotool/taskx"
)

type ReadCtx struct {
	buffer     *buffer.Buffer
	readingLen bool
	dataLen    int
}

func NewReadCtx() *ReadCtx {
	return &ReadCtx{buffer: buffer.NewBuffer(nil), readingLen: true}
}

func (r *ReadCtx) Buffer() *buffer.Buffer {
	return r.buffer
}

func (r *ReadCtx) IsReadingLen() bool {
	return r.readingLen
}

func (r *ReadCtx) SetReadingLen(b bool) {
	r.readingLen = b
}

func (r *ReadCtx) SetDataLen(i int) {
	r.dataLen = i
}

func (r *ReadCtx) GetDataLen() int {
	return r.dataLen
}

type IWriteCtx interface {
	DoWrite(PublicConn, *bytes.Buffer) error
}

type WriteToChanCtx struct {
	buffer chan *bytes.Buffer
}

func (w *WriteToChanCtx) Buffer() chan *bytes.Buffer {
	return w.buffer
}

const BufferFull errorx.ConstStringErr = "WriteChanFull"

func NewWriteToChanCtx() *WriteToChanCtx {
	return &WriteToChanCtx{buffer: make(chan *bytes.Buffer, 4096)}
}

func (w *WriteToChanCtx) DoWrite(conn PublicConn, data *bytes.Buffer) error {
	select {
	case w.buffer <- data:
		return nil
	default:
		return BufferFull
	}
}

type WriteInTaskPoolCtx struct {
	pool *taskx.Pool[any]
}

func NewWriteInTaskPoolCtx(pool *taskx.Pool[any]) *WriteInTaskPoolCtx {
	return &WriteInTaskPoolCtx{pool: pool}
}

func (w *WriteInTaskPoolCtx) DoWrite(conn PublicConn, data *bytes.Buffer) error {
	w.pool.AddTask(
		func() (any, error) {
			defer buffer.Return(data)
			err := conn.LowerWrite(data.Bytes())
			if err != nil {
				conn.CloseConnectionAllCallback("write error: " + err.Error())
			}
			return nil, err
		},
		taskx.NewAsyncCall(func(t any, err error) {
			if err != nil {
				Log.Warnf("write to connection error: %v", err)
			}
		}),
		conn.GetConnectionId())
	return nil
}
